;loader.asm load kernel into memory  

;for simplicity,kernel are assumed 256KB large  
;64KB*4 
;update es:bx when reading 64KB using int 13h  
;when reading 64KB  
;and start from track 1,sector 1 of floppy  

;still working at real mode 
%define _LOADER_ASM_ 1 
%define _LOADER_MAC_EXTERN_OR_GLOBAL_ 1 

%include "../include/boot.mac" 
%include "../include/loader.mac" 
%include "../include/parse_elf.mac" 
%include "../include/utils.mac" 

;text segment 
[section .text]
main:
	;initialize register  
	mov ax,LOADER_ELF_SEG  
	mov ds,ax ;data segment  

	mov ax,LOADER_STACK_SEG 
	mov ss,ax  
	mov sp,LOADER_STACK_SP  

;display 'Loading kernel......'  string  
	call clear_screen_via_bios ;clear screen 
	;show string"Loading kernel......" 
	SHOW_STRING_VIA_BIOS loading_kernel,loading_kernel_len 

read_kernel_elf: ;read kernel which is elf format  
	;read sector interrupt 
	;int 13h,read to:es:bx   
	mov ax,KERNEL_ELF_SEG  
	mov es,ax   
	mov bx,KERNEL_ELF_OFF  

.read_more:  
	;get track number and first sector to read  
	;int 13H  
	mov ax,word[total_sectors] 
	div byte [sectors_per_track];18 sectors per track   

	;get track number and first sector number 
	;Q=total/18 
	;if Q is even,track number is:Q/2,head=1 
	;else,track number:Q/2+1,head=0 
.quotient_even: 
	test al,0x01 
	jnz .quotient_odd ;odd 
	shr al,1 ;Q/2 
	mov ch,al 
	mov dh,0x01 ;head 1  
	mov dl,0x00 ;drive A  
	jmp .first_sector ;jmp to first sector  

.quotient_odd: 
	shr al,1 
	mov ch,al 
	inc ch 
	mov dh,0x00 ;head 0  
	mov dl,0x00 ;drive A  
	jmp .first_sector ;jmp to first sector  
	 
.first_sector: 
	;first sector number(1-18) 
	mov cl,ah   
	inc cl     

	;get sector count  
	;sector count is:18 - (first_sector -1) if current 
	;track left sectors is less then left_per_64kb  
	mov al,19   
	sub al,cl  
	cmp al,[left_sectors_per_64kb]  
	jb .read_track   

.read_left: ;largar than left,read left  
	mov al,[left_sectors_per_64kb]  
	jmp .read_track 

.read_track: 
	mov ah,READ_SYS_FUN  
	int 13h  
	jc .read_error  ;read error 

	;update total sectors have read 
	;al:int 13h,actual bytes have read  
	;update sectors left to read per 64kb 
	add word [total_sectors],ax    
	sub [left_sectors_per_64kb],al  

	;update bx 
	;al*512,al:actual sectors have read 
	;ax never exceed 18,so bytes never exceed 9216    
	mov cl,9 
	shl ax,cl ;ax*512  
	add bx,ax ;update bx  

	cmp byte [left_sectors_per_64kb],0x00 ;left sectors larger than 0 
	jnbe .read_more ;larger than 0,read again   

;update es and  total sectors,left sectors simultaneously  
.update_segment_es:   
	mov ax,es   
	add ax,0x1000 
	mov es,ax   
	mov bx,0x0000   

	;update left secors per 64kb 
	mov byte [left_sectors_per_64kb],0x80 ;128 sectors,64KB  

	cmp ax,MAX_SEG ;max segent:0x6000,have read 256kb 
	jb .read_more  
	jmp .read_ok   
	
.read_error: ;read error  
	call clear_screen_via_bios ;clear screen  

	reset_drive ;reset drive   
	jmp .read_more  

.read_ok: ;read ok,jump to 0x500 to execute sys_pm.asm   
	call clear_screen_via_bios ;clear screen 

	;parse kernel which is elf format 
	CLEAR_REGS_MULTI_XOR ax,esi,edi 
	;get kernel segments' total size 
	mov esi,KERNEL_ELF_START_ADDR 
	mov edi,kernel_seg_size 
	mov ax,word[esi+E_PHNUM_FILE_OFF] ;e_phnum 
	push esi 
	push edi 
	push ax 
	call get_seg_size_in_ph 

	;get kernel program header table size 
	mov edi,kernel_ph_table_size 
	push esi 
	push edi 
	call get_ph_table_size 

	;copy all segments to KERNEL_ELF_START_ADDR 
	mov edi,KERNEL_ELF_START_ADDR 
	mov esi,E_HEADER_SIZE 
	add esi,dword[kernel_ph_table_size] 
	push edi 
	push esi 
	push dword[kernel_seg_size] 
	call memory_copy  

	;get memory information:size,memory map entries etc. 
	call pmm_get_memory_info 
	GET_MEMORY_INFO_ADDRESS 

	;execute kernel. 
	JMP_TO_KERNEL 

;data segment 
[section .data] 
	;loading tips 
	loading_kernel db 'Loading kernel......' 
	loading_kernel_len equ $ - loading_kernel    

	total_sectors dw 0x00  ;total sectors have read  
	left_sectors_per_64kb db 0x80 ;left sectors to read per 64kb,init value:128(0x80)  
	sectors_per_track db 18 ;18 sectors per track 

	kernel_seg_size dd 0 ;total size of all segments in kernel 
	kernel_ph_table_size dd 0 ;program header table size in kernel 
